//============================================================================
// Name        : BackProjection.cpp
// Author      : Dailos
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================

#include <iostream>
#include <cv.h>
#include <highgui.h>

using namespace std;
void create_histogram_image(IplImage* gray_img, IplImage* hist_img);
void draw_histogram(CvHistogram *hist, IplImage* hist_img);

int main(int argc, char** argv)
{
	IplImage* img = cvLoadImage("../Tema2a.jpg");
	IplImage* imgIn = cvCreateImage( cvGetSize(img), IPL_DEPTH_8U, 1 );
	cvCvtColor( img, imgIn, CV_BGR2GRAY );
	IplImage* back_img = cvCreateImage( cvGetSize( imgIn ), IPL_DEPTH_8U, 1 );

	// Build and fill the reference histogram
    int hist_size = 256;
    float range[] = { 0, 256 };
    float* ranges[] = { range };
	CvHistogram* hist_ref;
	hist_ref = cvCreateHist( 1, &hist_size, CV_HIST_ARRAY, ranges, 1 );
	for(unsigned int ind=0;ind<256;++ind)
	{
	  (*cvGetHistValue_1D( hist_ref, ind )) = 100.0*(1.0/255.0);
	}

	CvHistogram* hist_src;
	hist_src = cvCreateHist( 1, &hist_size, CV_HIST_ARRAY, ranges, 1 );
	cvCalcHist( &imgIn, hist_src, 0, NULL );
	cvNormalizeHist(hist_src, 100.0);
	// Get the minimum and maximum values of the histogram
	float min, max;
    cvGetMinMaxHistValue( hist_ref, &min, &max);
    cout << "minHistRef: " << min << " maxHistRef: " << max << endl;
    cvGetMinMaxHistValue( hist_src, &min, &max);
    cout << "minHistSrc: " << min << " maxHistSrc: " << max << endl;
	//cvNormalizeHist( hist_ref, 20*255 ); // Normalize it

	cvCalcBackProject( &imgIn, back_img, hist_ref );// Calculate back projection

	//cvNormalizeHist( hist_ref, 20*255.0 );

	IplImage *hist_img = cvCreateImage(cvSize(300,240), 8, 1);
    cvSet( hist_img, cvScalarAll(255), 0 );

    IplImage *hist_out_img = cvCreateImage(cvSize(300,240), 8, 1);
    cvSet( hist_out_img, cvScalarAll(255), 0 );

    IplImage *hist_ref_img = cvCreateImage(cvSize(300,240), 8, 1);
    cvSet( hist_ref_img, cvScalarAll(255), 0 );

	create_histogram_image(back_img, hist_out_img);
	draw_histogram(hist_ref, hist_ref_img);
	create_histogram_image(imgIn, hist_img);

	// Show images
	cvNamedWindow( "Source", 1) ;
	cvShowImage( "Source", imgIn );
	cvNamedWindow( "Back Projection", 1) ;
	cvShowImage( "Back Projection", back_img );
	cvNamedWindow( "Histogram In", 1) ;
	cvShowImage( "Histogram In", hist_img );
	cvNamedWindow( "Histogram Out", 1) ;
	cvShowImage( "Histogram Out", hist_out_img );
	cvNamedWindow( "Reference Histogram", 1) ;
	cvShowImage( "Reference Histogram", hist_ref_img );


	cvWaitKey(0);

	cvReleaseImage( &img );
	cvReleaseImage( &back_img );
	cvReleaseImage( &hist_img );
	return 0;
}

void create_histogram_image(IplImage* gray_img, IplImage* hist_img)
{
  CvHistogram *hist;
  int hist_size = 256;
  float range[]={0,256};
  float* ranges[] = { range };
  float max_value = 0.0, min_value = 0.0;
  float w_scale = 0.0;

  // create array to hold histogram values
  hist = cvCreateHist(1, &hist_size, CV_HIST_ARRAY, ranges, 1);

  // calculate histogram values
  cvCalcHist( &gray_img, hist, 0, NULL );

  // Get the minimum and maximum values of the histogram
  cvGetMinMaxHistValue( hist, &min_value, &max_value);
  cout << "min: " << min_value << " max: " << max_value << endl;

  // set height by using maximim value
  cvScale( hist->bins, hist->bins, ((float)hist_img->height)/max_value, 0 );

  // calculate width
  w_scale = ((float)hist_img->width)/hist_size;

  // plot the histogram
  for( int i = 0; i < hist_size; i++ )
  {
    cvRectangle( hist_img, cvPoint((int)i*w_scale , hist_img->height),
	             cvPoint((int)(i+1)*w_scale, hist_img->height - cvRound(cvGetReal1D(hist->bins,i))),
	             cvScalar(0), -1, 8, 0 );
  }
}

void draw_histogram(CvHistogram *hist, IplImage* hist_img)
{
  int hist_size = 256;
  float max_value = 0.0, min_value = 0.0;
  float w_scale = 0.0;

  // Get the minimum and maximum values of the histogram
  cvGetMinMaxHistValue( hist, &min_value, &max_value);

  // set height by using maximim value
  cvScale( hist->bins, hist->bins, ((float)hist_img->height)/max_value, 0 );

  // calculate width
  w_scale = ((float)hist_img->width)/hist_size;

  // plot the histogram
  for( int i = 0; i < hist_size; i++ )
  {
    cvRectangle( hist_img, cvPoint((int)i*w_scale , hist_img->height),
                 cvPoint((int)(i+1)*w_scale, hist_img->height - cvRound(cvGetReal1D(hist->bins,i))),
                  cvScalar(0), -1, 8, 0 );
  }
}
